package lumis.portal.serviceinterfaceinstance;

import lumis.portal.PortalException;
import lumis.portal.UnexpectedException;
import lumis.portal.cache.ICloneableCacheEntry;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.serialization.operation.ICloneableConfig;
import lumis.portal.serviceinterface.IServiceInterfaceManager;
import lumis.portal.stability.StableMinor;
import lumis.util.XmlUtil;

import java.io.OutputStream;

import org.w3c.dom.Node;

/**
 * Holds the data about a service interface instance.
 *
 * @since 4.0.0
 * @version $Revision: 13220 $ $Date: 2011-07-08 13:52:53 -0300 (Fri, 08 Jul 2011) $
 */
@StableMinor(version = "6.0", sinceVersion = "4.0")
public class ServiceInterfaceInstanceConfig implements ICloneableCacheEntry, ICloneableConfig<ServiceInterfaceInstanceConfig>
{
	// Inherit constants
	public static final int PRINT_INTERFACE_INHERIT = 2;
	public static final int PRINT_INTERFACE_YES = 1;
	public static final int PRINT_INTERFACE_NO = 0;
	public static final int RENDER_AS_INHERIT = 2;
	public static final int ENABLE_CACHE_INHERIT = 2;
	public static final int CACHE_LEVEL_INHERIT = 2;
	public static final int CACHE_PERSONALIZATION_INHERIT = 3;
	public static final int CACHE_SERVER_SIDE_INCLUDE_NO = 0;
	public static final int CACHE_SERVER_SIDE_INCLUDE_YES = 1;
	public static final int CACHE_SERVER_SIDE_INCLUDE_INHERIT = 2;

	private String id;
	private String serviceInstanceId;
	private String serviceInterfaceId;
	private String pageId;
	private String owner;
	private String parentInterfaceInstanceId;
	private String serviceInterfaceStyleId;
	private boolean createdRunTime = false;

	private String displayName;
	private String title;
	private String width;
	private String height;
	private String paddingLeft;
	private String paddingRight;
	private String paddingTop;
	private String paddingBottom;
	private Integer colspan;
	private Integer rowspan;
	private int printable = PRINT_INTERFACE_INHERIT;
	private Integer holderPriority;
	private int renderAs = RENDER_AS_INHERIT;
	private int enableCache = ENABLE_CACHE_INHERIT;
	private int cacheLevel = CACHE_LEVEL_INHERIT;
	private int cachePersonalization = CACHE_PERSONALIZATION_INHERIT;
	private int cacheServerSideInclude = CACHE_SERVER_SIDE_INCLUDE_INHERIT;
	private boolean showTitleBar = false;
	private boolean disableInContextEdit = false;

	public ServiceInterfaceInstanceConfig()
	{
		super();
	}

	public ServiceInterfaceInstanceConfig(ServiceInterfaceInstanceConfig copy) throws Exception
	{
		// TODO: Here the setter methods must be used instead of accessing the private members (for example, it's bypassing the logic of setInterfaceInstanceData method)
		this.serviceInstanceId = copy.getServiceInstanceId();
		this.serviceInterfaceId = copy.getServiceInterfaceId();
		this.setOwner(copy.getOwner().getClass().getName());
		this.pageId = copy.pageId;
		this.parentInterfaceInstanceId = copy.getParentInterfaceInstanceId();
		this.serviceInterfaceStyleId = copy.getServiceInterfaceStyleId();
		this.displayName = copy.getDisplayName();
		this.title = copy.getTitle();
		this.width = copy.getWidth();
		this.height = copy.getHeight();
		this.paddingLeft = copy.getPaddingLeft();
		this.paddingRight = copy.getPaddingRight();
		this.paddingTop = copy.getPaddingTop();
		this.paddingBottom = copy.getPaddingBottom();
		this.colspan = copy.getColspan();
		this.rowspan = copy.getRowspan();
		this.printable = copy.getPrintable();
		this.holderPriority = copy.getHolderPriority();
		this.renderAs = copy.getRenderAs();
		this.enableCache = copy.getEnableCache();
		this.cacheLevel = copy.getCacheLevel();
		this.cachePersonalization = copy.getCachePersonalization();
		this.cacheServerSideInclude = copy.getCacheServerSideInclude();
		this.showTitleBar = copy.isShowTitleBar();
		this.disableInContextEdit = copy.isInContextEditDisabled();
		// setCreatedRunTime(copy.isCreatedRunTime());
	}

	@Override
	public ServiceInterfaceInstanceConfig clone() throws CloneNotSupportedException
	{
		return (ServiceInterfaceInstanceConfig)super.clone();
	}

	/**
	 * @return Returns the id.
	 */
	public String getId()
	{
		return id;
	}

	/**
	 * @param id
	 *            The id to set.
	 */
	public void setId(String id)
	{
		this.id = id;
	}

	public boolean isInterfaceHolder()
	{
		return serviceInterfaceId.equals(IServiceInterfaceManager.INTERFACE_HOLDER_ID);
	}

	/**
	 * @return Returns the serviceInterfaceId.
	 */
	public String getServiceInterfaceId()
	{
		return serviceInterfaceId;
	}

	/**
	 * @param serviceInterfaceId
	 *            The serviceInterfaceId to set.
	 */
	public void setServiceInterfaceId(String interfaceId)
	{
		this.serviceInterfaceId = interfaceId;
	}

	/**
	 * @return Returns the serviceInstanceId.
	 */
	public String getServiceInstanceId()
	{
		return serviceInstanceId;
	}

	/**
	 * @param serviceInstanceId
	 *            The serviceInstanceId to set.
	 */
	public void setServiceInstanceId(String serviceInstanceId)
	{
		this.serviceInstanceId = serviceInstanceId;
	}

	/**
	 * @return Returns the serviceInterfaceStyleId.
	 */
	public String getServiceInterfaceStyleId()
	{
		return serviceInterfaceStyleId;
	}

	/**
	 * @param serviceInterfaceStyleId
	 *            The serviceInterfaceStyleId to set.
	 */
	public void setServiceInterfaceStyleId(String styleId)
	{
		this.serviceInterfaceStyleId = styleId;
	}

	/**
	 * @return Returns the pageId.
	 */
	public String getPageId()
	{
		return pageId;
	}

	/**
	 * Sets the page id for this Service Interface Instance.  If the service interface instance has had its owner info already set,
	 * this owner info will be discarded and the page will become it's owner. For further information, see {@link #setOrphan(String)}.
	 * @param pageId The pageId to set.
	 */
	public void setPageId(String pageId)
	{
		if(pageId != null && !"".equals(pageId))
		{
			this.setOwner(PageInterfaceInstanceOwner.class.getName());
		}
		this.pageId = pageId;
	}

	public String getParentInterfaceInstanceId()
	{
		return parentInterfaceInstanceId;
	}

	public void setParentInterfaceInstanceId(String parentInterfaceInstanceId)
	{
		this.parentInterfaceInstanceId = parentInterfaceInstanceId;
	}

	/**
	 * Created Run Time indicates if the interface instance was created runtime,
	 * or if it was explicitly dragged and dropped into a page layout.
	 *
	 * @return
	 */
	public boolean isCreatedRunTime()
	{
		return createdRunTime;
	}

	/**
	 * Created Run Time indicates if the interface instance was created runtime,
	 * or if it was explicitly dragged and dropped into a page layout.
	 *
	 * @param createdRunTime
	 */
	public void setCreatedRunTime(boolean isCreatedRunTime)
	{
		this.createdRunTime = isCreatedRunTime;
	}

	/**
	 * Returns the display name to be used for this service interface instance.
	 * <p>
	 * The display name is usually the name used for referring to the service
	 * interface instance for a developer or administrator.
	 * @return the display name.
	 * @since 5.5.0
	 */
	public String getDisplayName()
	{
		return displayName;
	}

	/**
	 * Sets the display name for this service interface instance.
	 * @param displayName the display name.
	 * @see #getDisplayName()
	 * @since 5.5.0
	 */
	public void setDisplayName(String displayName)
	{
		this.displayName = displayName;
	}

	public String getTitle()
	{
		return title;
	}

	public void setTitle(String title)
	{
		this.title = title;
	}

	public Integer getColspan()
	{
		return colspan;
	}

	public void setColspan(Integer colspan)
	{
		this.colspan = colspan;
	}

	public String getHeight()
	{
		return height;
	}

	public void setHeight(String height)
	{
		this.height = height;
	}

	public int getPrintable()
	{
		return printable;
	}

	public void setPrintable(int printable)
	{
		this.printable = printable;
	}

	public String getPaddingBottom()
	{
		return paddingBottom;
	}

	public void setPaddingBottom(String paddingBottom)
	{
		this.paddingBottom = paddingBottom;
	}

	public String getPaddingLeft()
	{
		return paddingLeft;
	}

	public void setPaddingLeft(String paddingLeft)
	{
		this.paddingLeft = paddingLeft;
	}

	public String getPaddingRight()
	{
		return paddingRight;
	}

	public void setPaddingRight(String paddingRight)
	{
		this.paddingRight = paddingRight;
	}

	public String getPaddingTop()
	{
		return paddingTop;
	}

	public void setPaddingTop(String paddingTop)
	{
		this.paddingTop = paddingTop;
	}

	public Integer getRowspan()
	{
		return rowspan;
	}

	public void setRowspan(Integer rowspan)
	{
		this.rowspan = rowspan;
	}

	public String getWidth()
	{
		return width;
	}

	public void setWidth(String width)
	{
		this.width = width;
	}

	public Integer getHolderPriority()
	{
		return holderPriority;
	}

	public void setHolderPriority(Integer holderPriority)
	{
		this.holderPriority = holderPriority;
	}

	/**
	 * @return Returns the renderAs.
	 */

	public int getRenderAs()
	{
		return renderAs;
	}
	/**
	 * @param renderAs The renderAs to set.
	 */
	public void setRenderAs(int renderAs)
	{
		this.renderAs = renderAs;
	}

	/**
	 * @return Returns the enableCache.
	 */

	public int getEnableCache()
	{
		return enableCache;
	}
	/**
	 * @param enableCache The enableCache to set.
	 */
	public void setEnableCache(int enableCache)
	{
		this.enableCache = enableCache;
	}

	/**
	 * @return Returns the cacheLevel.
	 */

	public int getCacheLevel()
	{
		return cacheLevel;
	}
	/**
	 * @param cacheLevel The cacheLevel to set.
	 */
	public void setCacheLevel(int cacheLevel)
	{
		this.cacheLevel = cacheLevel;
	}

	/**
	 * @return Returns the cachePersonalization.
	 */

	public int getCachePersonalization()
	{
		return cachePersonalization;
	}
	/**
	 * @param cachePersonalization The cachePersonalization to set.
	 */
	public void setCachePersonalization(int cachePersonalization)
	{
		this.cachePersonalization = cachePersonalization;
	}

	/**
	 * @return Returns the cacheServerSideInclude.
	 */

	public int getCacheServerSideInclude()
	{
		return cacheServerSideInclude;
	}
	/**
	 * @param cacheServerSideInclude The cacheServerSideInclude to set.
	 */
	public void setCacheServerSideInclude(int cacheServerSideInclude)
	{
		this.cacheServerSideInclude = cacheServerSideInclude;
	}

	public boolean isShowTitleBar()
	{
		return showTitleBar;
	}

	public void setShowTitleBar(boolean showTitleBar)
	{
		this.showTitleBar = showTitleBar;
	}

	public boolean isInContextEditDisabled()
	{
		return disableInContextEdit;
	}

	public void setDisableInContextEdit(boolean disableInContextEdit)
	{
		this.disableInContextEdit = disableInContextEdit;
	}

	public void serialize(ServiceInterfaceInstanceConfig serviceInterfaceInstanceConfig, OutputStream outputStream) throws PortalException
	{
		try
		{
			StringBuilder stream = new StringBuilder();

			stream.append("<serviceInterfaceInstance id=\""+getId()+"\">");
			if (getOwner() != null)
				stream.append("<owner>" + XmlUtil.encodeXml(getOwner().getClass().getName())
					+ "</owner>");
			stream.append("<pageId>" + XmlUtil.encodeXml(getPageId()) + "</pageId>");
			stream.append("<parentInterfaceInstanceId>"+(getParentInterfaceInstanceId() == null ? "" : getParentInterfaceInstanceId())+"</parentInterfaceInstanceId>");
			stream.append("<cacheLevel>"+getCacheLevel()+"</cacheLevel>");
			stream.append("<cachePersonalization>"+getCachePersonalization()+"</cachePersonalization>");
			stream.append("<cacheServerSideInclude>"+getCacheServerSideInclude()+"</cacheServerSideInclude>");
			stream.append("<colspan>"+(getColspan() == null ? "" : getColspan())+"</colspan>");
			stream.append("<rowspan>"+(getRowspan() == null ? "" : getRowspan())+"</rowspan>");
			stream.append("<createdRunTime>"+isCreatedRunTime()+"</createdRunTime>");
			stream.append("<enableCache>"+getEnableCache()+"</enableCache>");
			stream.append("<height>"+(getHeight() == null ? "" : getHeight())+"</height>");
			stream.append("<width>"+(getWidth() == null ? "" : getWidth())+"</width>");
			stream.append("<holderPriority>"+(getHolderPriority() == null ? "" : getHolderPriority())+"</holderPriority>");
			stream.append("<paddingBottom><![CDATA["+(getPaddingBottom() == null ? "" : getPaddingBottom())+"]]></paddingBottom>");
			stream.append("<paddingLeft><![CDATA["+(getPaddingLeft() == null ? "" : getPaddingLeft())+"]]></paddingLeft>");
			stream.append("<paddingRight><![CDATA["+(getPaddingRight() == null ? "" : getPaddingRight())+"]]></paddingRight>");
			stream.append("<paddingTop><![CDATA["+(getPaddingTop() == null ? "" : getPaddingTop())+"]]></paddingTop>");
			stream.append("<displayName>" + XmlUtil.encodeXml(getDisplayName()) + "</displayName>");
			stream.append("<title>" + XmlUtil.encodeXml(getTitle()) + "</title>");
			stream.append("<createdRunTime>"+isCreatedRunTime()+"</createdRunTime>");
			stream.append("<printable>"+getPrintable()+"</printable>");
			stream.append("<renderAs>"+getRenderAs()+"</renderAs>");
			stream.append("<showTitleBar>"+isShowTitleBar()+"</showTitleBar>");
			stream.append("<disableInContextEdit>"+isInContextEditDisabled()+"</disableInContextEdit>");
			stream.append("<serviceInstanceId>" + (getServiceInstanceId() == null ? "" : getServiceInstanceId()) + "</serviceInstanceId>");
			stream.append("<serviceInterfaceId>"+getServiceInterfaceId()+"</serviceInterfaceId>");
			stream.append("<serviceInterfaceStyleId><![CDATA["+(getServiceInterfaceStyleId() == null ? "" : getServiceInterfaceStyleId())+"]]></serviceInterfaceStyleId>");
			stream.append("</serviceInterfaceInstance>");

			outputStream.write(stream.toString().getBytes("UTF-8"));
		}
		/*catch(PortalException e)
		{
			throw e;
		}*/
		catch(Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	public void deserialize(Node serviceInterfaceInstanceNode) throws PortalException
	{
		try
		{
			setId(XmlUtil.readAttributeString("id", serviceInterfaceInstanceNode));
			this.owner = XmlUtil.readNodeString("owner", serviceInterfaceInstanceNode);
			setPageId(XmlUtil.readNodeString("pageId", serviceInterfaceInstanceNode));
			setParentInterfaceInstanceId(XmlUtil.readNodeString("parentInterfaceInstanceId", serviceInterfaceInstanceNode));
			setCreatedRunTime(XmlUtil.readNodeBoolean("createdRunTime", serviceInterfaceInstanceNode, isCreatedRunTime()));
			setCacheLevel(XmlUtil.readNodeInt("cacheLevel", serviceInterfaceInstanceNode, getCacheLevel()));
			setCachePersonalization(XmlUtil.readNodeInt("cachePersonalization", serviceInterfaceInstanceNode, getCachePersonalization()));
			setCacheServerSideInclude(XmlUtil.readNodeInt("cacheServerSideInclude", serviceInterfaceInstanceNode, getCacheServerSideInclude()));
			setColspan(XmlUtil.readNodeInteger("colspan", serviceInterfaceInstanceNode, null));
			setRowspan(XmlUtil.readNodeInteger("rowspan", serviceInterfaceInstanceNode, null));
			setCreatedRunTime(XmlUtil.readNodeBoolean("createdRunTime", serviceInterfaceInstanceNode, isCreatedRunTime()));
			setEnableCache(XmlUtil.readNodeInt("enableCache", serviceInterfaceInstanceNode, getEnableCache()));
			setHeight(XmlUtil.readNodeString("height", serviceInterfaceInstanceNode));
			setWidth(XmlUtil.readNodeString("width", serviceInterfaceInstanceNode));
			setHolderPriority(XmlUtil.readNodeInteger("holderPriority", serviceInterfaceInstanceNode, null));
			setPaddingBottom(XmlUtil.readNodeString("paddingBottom", serviceInterfaceInstanceNode));
			setPaddingLeft(XmlUtil.readNodeString("paddingLeft", serviceInterfaceInstanceNode));
			setPaddingRight(XmlUtil.readNodeString("paddingRight", serviceInterfaceInstanceNode));
			setPaddingTop(XmlUtil.readNodeString("paddingTop", serviceInterfaceInstanceNode));
			setDisplayName(XmlUtil.readNodeString("displayName", serviceInterfaceInstanceNode));
			setTitle(XmlUtil.readNodeString("title", serviceInterfaceInstanceNode));
			setPrintable(XmlUtil.readNodeInt("printable", serviceInterfaceInstanceNode, getPrintable()));
			setRenderAs(XmlUtil.readNodeInt("renderAs", serviceInterfaceInstanceNode, getRenderAs()));
			setShowTitleBar(XmlUtil.readNodeBoolean("showTitleBar", serviceInterfaceInstanceNode, isShowTitleBar()));
			setDisableInContextEdit(XmlUtil.readNodeBoolean("disableInContextEdit", serviceInterfaceInstanceNode, isInContextEditDisabled()));
			setServiceInstanceId(XmlUtil.readNodeString("serviceInstanceId", serviceInterfaceInstanceNode));
			setServiceInterfaceId(XmlUtil.readNodeString("serviceInterfaceId", serviceInterfaceInstanceNode));
			setServiceInterfaceStyleId(XmlUtil.readNodeString("serviceInterfaceStyleId", serviceInterfaceInstanceNode));
		}
		catch(PortalException e)
		{
			throw e;
		}
		catch(Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	/**
	 * Returns true if all properties of this object are equals to the properties of the given object.
	 * @param ServiceInterfaceInstanceConfig the object to compare the properties with.
	 * @return true if the properties are equal, false otherwise.
	 * @since 5.6.0
	 */
	public boolean isIdentical(ServiceInterfaceInstanceConfig serviceInterfaceInstanceConfig)
	{
		try
		{
			return
					areEqual(this.id, serviceInterfaceInstanceConfig.id)
				&&	areEqual(this.serviceInstanceId, serviceInterfaceInstanceConfig.serviceInstanceId)
				&&	areEqual(this.serviceInterfaceId, serviceInterfaceInstanceConfig.serviceInterfaceId)
				&&	areEqual(this.pageId, serviceInterfaceInstanceConfig.pageId)
				&&	areEqual(this.getOwner().getClass().getName(), serviceInterfaceInstanceConfig.getOwner().getClass().getName())
				&&	areEqual(this.parentInterfaceInstanceId, serviceInterfaceInstanceConfig.parentInterfaceInstanceId)
				&&	areEqual(this.serviceInterfaceStyleId, serviceInterfaceInstanceConfig.serviceInterfaceStyleId)
				&&	areEqual(this.createdRunTime, serviceInterfaceInstanceConfig.createdRunTime)
				&&	areEqual(this.title, serviceInterfaceInstanceConfig.title)
				&&	areEqual(this.width, serviceInterfaceInstanceConfig.width)
				&&	areEqual(this.height, serviceInterfaceInstanceConfig.height)
				&&	areEqual(this.paddingLeft, serviceInterfaceInstanceConfig.paddingLeft)
				&&	areEqual(this.paddingRight, serviceInterfaceInstanceConfig.paddingRight)
				&&	areEqual(this.paddingTop, serviceInterfaceInstanceConfig.paddingTop)
				&&	areEqual(this.paddingBottom, serviceInterfaceInstanceConfig.paddingBottom)
				&&	areEqual(this.colspan, serviceInterfaceInstanceConfig.colspan)
				&&	areEqual(this.rowspan, serviceInterfaceInstanceConfig.rowspan)
				&&	areEqual(this.printable, serviceInterfaceInstanceConfig.printable)
				&&	areEqual(this.holderPriority, serviceInterfaceInstanceConfig.holderPriority)
				&&	areEqual(this.renderAs, serviceInterfaceInstanceConfig.renderAs)
				&&	areEqual(this.enableCache, serviceInterfaceInstanceConfig.enableCache)
				&&	areEqual(this.cacheLevel, serviceInterfaceInstanceConfig.cacheLevel)
				&&	areEqual(this.cachePersonalization, serviceInterfaceInstanceConfig.cachePersonalization)
				&&	areEqual(this.cacheServerSideInclude, serviceInterfaceInstanceConfig.cacheServerSideInclude)
				&&	areEqual(this.showTitleBar, serviceInterfaceInstanceConfig.showTitleBar)
				&&  areEqual(this.disableInContextEdit, serviceInterfaceInstanceConfig.disableInContextEdit);
		}
		catch (PortalException e)
		{
			throw new RuntimeException(e);
		}
	}

	private boolean areEqual(Object obj1, Object obj2)
	{
		return ((obj1 == obj2) || (obj1 != null && obj1.equals(obj2)));
	}

	/**
	 * Sets the owner class name.
	 *
	 * @param ownerClassName
	 *            the owner class name.
	 * @since 6.0.0
	 */
	void setOwner(String ownerClassName)
	{
		this.owner = ownerClassName;
	}

	/**
	 * Returns the owner.
	 *
	 * @return the owner
	 * @since 6.0.0
	 */
	public IServiceInterfaceInstanceOwner getOwner() throws PortalException
	{
		if (pageId != null || owner == null)
			return PageInterfaceInstanceOwner.getInstance();

		try
		{
			return ManagerFactory.getDeploymentManager().getClassLoader().loadClass(owner).asSubclass(
					IServiceInterfaceInstanceOwner.class).newInstance();
		}
		catch (Exception e)
		{
			throw new UnexpectedException(e);
		}
	}

	/**
	 * Sets the owner for this service interface instance.
	 * <p>
	 * When setting an interface instance orphan, you must set the owner for
	 * that interface instance. The page id will be set null once an
	 * interfaceInstance is set orphan.
	 * </p>
	 *
	 * @param ownerClass
	 *            the owner class of the orphan interface instance.
	 * @throws IllegalArgumentException
	 *             in case the owner is null
	 * @since 6.0.0
	 * @see IServiceInterfaceInstanceOwner
	 */
	public void setOrphan(Class<? extends IServiceInterfaceInstanceOwner> ownerClass)
	{
		if (ownerClass == null)
			throw new IllegalArgumentException("owner cannot be null");

		this.pageId = null;
		this.owner = ownerClass.getName();
	}
}
